文件描述符

文件描述符 fd file descriptor

文件描述符背景及什么是文件描述符?

文件描述符背景?
Linux 系统中,把一切都看做是文件 (包括普通文件、目录文件、链接文件、Socket 及设备驱动等)。在操作这些文件时,每操作一次就找一次名字,会耗费大量的时间和效率,所以 Linux 中规定每一个文件对应一个索引,这样要操作文件的时候,直接找到索引就可以对其进行操作了。
什么是文件描述符?
当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符,文件描述符就是内核为了高效管理已被打开的文件所创建的索引,用来指向被打开的文件,所有执行 I/O 操作的系统调用都会通过文件描述符来实现。

进程文件描述表格 fd table

Linux 内核对所有打开的文件有一个文件描述符表格,里面存储了每个文件描述符作为索引与一个打开文件相对应的关系。

一个数组,文件描述符就是文件描述符表这个数组的下标,数组的内容就是指向一个个打开的文件的指针。

image.png|400
实际上,Linux 内核维护了 3 个数据结构,建立了三个表:

  1. 进程级的文件描述符表
  2. 系统级的打开文件描述符表
  3. 文件系统的 i-node 表

一个 Linux 进程启动后,会在内核空间中创建一个 PCB 控制块,PCB 内部有一个文件描述符表 (fd table),记录着当前进程所有可用的 fd,即当前进程所有打开的文件。进程级的描述符表的每一条记录了单个进程所使用的 fd 的相关信息,进程之间互相独立,一个进程使用了 fd:3,另一个进程也可以用 3。
image.png|500
可见:

fd 如何定位文件

当需要执行 I/O 操作时,会传入 fd 作为参数,先从进程文件描述表查找该 fd 对应的哪个条目,取出对应的那个已经打开的文件的句柄,根据文件句柄指向,去系统 fd 表中查找到该文件指向的 inode,从而定位到该文件的真正位置,进行 I/O 操作。

文件、文件描述符和进程

文件描述符限制

内核对 fd 有系统级的限制,以及用户级限制,不让某一个应用进程消耗掉所有的文件资源,可以使用 ulimit -n 查看。

FD 的一些疑惑

文件句柄和文件描述符

什么是文件描述符?
File descriptor 简称 fd,当应用程序打开/新建一个文件时,内核会返回给应用程序一个文件描述符对应这个打开/创建的文件,fd 本质是一个非负整数,是一个索引值,对应于该应用程序所维护该进程所打开的文件记录表中元素的索引值。
什么是句柄?
句柄:句柄可以理解为 windows 下的文件描述符。

每个文件的文件描述符是固定的吗?

不是固定的,尽管是同一个文件,得到 FD 却不一样。

FD 每次都是从 3 开始的?

因为 0、1、2 被占用了,系统创建的每个进程默认会打开 3 个文件:

FD 是递增的吗?

文件描述符不是递增的,文件描述符被回收后是可以再次分配的。

open 文件的示例

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int main(int argc, char* argv[]) {
	// 以只读模式打开 demo.txt 文件
	int fd = open("demo.txt", O_RDONLY);
	if (fd == -1) {
		perror("open demo.txt error\n");
		return EXIT_FAILURE;
	}
	// 打印获取到的文件描述符
	printf("demo.txt fd = %d \n", fd);
	return EXIT_SUCCESS;
}